/*
* Copyright (C)
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* ScriptData
SDName: instance_zulaman
SD%Complete: 80
SDComment:
SDCategory: Zul'Aman
EndScriptData */

#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "zulaman.h"
#include "Player.h"
#include "TemporarySummon.h"

enum Misc
{
	MAX_ENCOUNTER = 7,
	RAND_VENDOR = 2,
	WORLDSTATE_SHOW_TIMER = 3104,
	WORLDSTATE_TIME_TO_SACRIFICE = 3106
};

// Chests spawn at bear/eagle/dragonhawk/lynx bosses
// The loots depend on how many bosses have been killed, but not the entries of the chests
// But we cannot add loots to gameobject, so we have to use the fixed loot_template
struct SHostageInfo
{
	uint32 npc, go; // FIXME go Not used
	float x, y, z, o;
};

static SHostageInfo HostageInfo[] =
{
	{ 23790, 186648, -57, 1343, 40.77f, 3.2f }, // bear
	{ 23999, 187021, 400, 1414, 74.36f, 3.3f }, // eagle
	{ 24001, 186672, -35, 1134, 18.71f, 1.9f }, // dragonhawk
	{ 24024, 186667, 413, 1117, 6.32f, 3.1f }  // lynx
};

Position const HarrisonJonesLoc = { 120.687f, 1674.0f, 42.0217f, 1.59044f };

class instance_zulaman : public InstanceMapScript
{
public:
	instance_zulaman()
		: InstanceMapScript("instance_zulaman", 568) { }

	struct instance_zulaman_InstanceMapScript : public InstanceScript
	{
		instance_zulaman_InstanceMapScript(Map* map) : InstanceScript(map) {}

		uint64 HarkorsSatchelGUID;
		uint64 TanzarsTrunkGUID;
		uint64 AshlisBagGUID;
		uint64 KrazsPackageGUID;
		uint64 StrangeGongGUID;
		uint64 HarrisonJonesGUID;

		uint64 HexLordGateGUID;
		uint64 ZulJinGateGUID;
		uint64 MassiveGateGUID;
		uint64 AkilzonDoorGUID;
		uint64 ZulJinDoorGUID;
		uint64 HalazziDoorGUID;

		uint32 QuestTimer;
		uint16 BossKilled;
		uint16 QuestMinute;
		uint16 ChestLooted;

		uint32 m_auiEncounter[MAX_ENCOUNTER];
		uint32 RandVendor[RAND_VENDOR];

		void Initialize()
		{
			memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));

			HarkorsSatchelGUID = 0;
			TanzarsTrunkGUID = 0;
			AshlisBagGUID = 0;
			KrazsPackageGUID = 0;
			StrangeGongGUID = 0;
			HexLordGateGUID = 0;
			ZulJinGateGUID = 0;
			MassiveGateGUID = 0;
			AkilzonDoorGUID = 0;
			HalazziDoorGUID = 0;
			ZulJinDoorGUID = 0;

			HarrisonJonesGUID = 0;

			QuestTimer = 0;
			QuestMinute = 0;
			BossKilled = 0;
			ChestLooted = 0;

			for (uint8 i = 0; i < RAND_VENDOR; ++i)
				RandVendor[i] = NOT_STARTED;

			m_auiEncounter[DATA_GONGEVENT] = NOT_STARTED;
		}

		bool IsEncounterInProgress() const
		{
			for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
			if (m_auiEncounter[i] == IN_PROGRESS)
				return true;

			return false;
		}

		void OnPlayerEnter(Player* /*player*/)
		{
			if (!HarrisonJonesGUID)
				instance->SummonCreature(NPC_HARRISON_JONES, HarrisonJonesLoc);
		}

		void OnCreatureCreate(Creature* creature)
		{
			switch (creature->GetEntry())
			{
			case NPC_HARRISON_JONES:
				HarrisonJonesGUID = creature->GetGUID();
				break;
			case NPC_JANALAI:
			case NPC_ZULJIN:
			case NPC_HEXLORD:
			case NPC_HALAZZI:
			case NPC_NALORAKK:
			default:
				break;
			}
		}

		void OnGameObjectCreate(GameObject* go)
		{
			switch (go->GetEntry())
			{
			case GO_DOOR_HALAZZI: HalazziDoorGUID = go->GetGUID();break;
			case GO_GATE_ZULJIN: ZulJinGateGUID = go->GetGUID(); break;
			case GO_GATE_HEXLORD: HexLordGateGUID = go->GetGUID(); break;
			case GO_MASSIVE_GATE: MassiveGateGUID = go->GetGUID(); break;
			case GO_DOOR_AKILZON: AkilzonDoorGUID = go->GetGUID(); break;
			case GO_DOOR_ZULJIN: ZulJinDoorGUID = go->GetGUID(); break;

			case GO_HARKORS_SATCHEL: HarkorsSatchelGUID = go->GetGUID(); break;
			case GO_TANZARS_TRUNK: TanzarsTrunkGUID = go->GetGUID(); break;
			case GO_ASHLIS_BAG: AshlisBagGUID = go->GetGUID(); break;
			case GO_KRAZS_PACKAGE: KrazsPackageGUID = go->GetGUID(); break;
			case GO_STRANGE_GONG: StrangeGongGUID = go->GetGUID(); break;
			default: break;
			}
			CheckInstanceStatus();
		}

		void SummonHostage(uint8 num)
		{
			if (!QuestMinute)
				return;

			Map::PlayerList const &PlayerList = instance->GetPlayers();
			if (PlayerList.isEmpty())
				return;

			Map::PlayerList::const_iterator i = PlayerList.begin();
			if (Player* i_pl = i->GetSource())
			{
				if (Unit* Hostage = i_pl->SummonCreature(HostageInfo[num].npc, HostageInfo[num].x, HostageInfo[num].y, HostageInfo[num].z, HostageInfo[num].o, TEMPSUMMON_DEAD_DESPAWN, 0))
				{
					Hostage->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
					Hostage->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
				}
			}
		}

		void CheckInstanceStatus()
		{
			if (BossKilled >= DATA_HALAZZIEVENT)
				HandleGameObject(HexLordGateGUID, true);

			if (BossKilled >= DATA_HEXLORDEVENT)
				HandleGameObject(ZulJinGateGUID, true);
		}

		std::string GetSaveData()
		{
			OUT_SAVE_INST_DATA;

			std::ostringstream ss;
			ss << "S " << BossKilled << ' ' << ChestLooted << ' ' << QuestMinute;

			OUT_SAVE_INST_DATA_COMPLETE;
			return ss.str();
		}

		void Load(const char* load)
		{
			if (!load)
				return;

			std::istringstream ss(load);
			//sLog->outError("Zul'aman loaded, %s.", ss.str().c_str());
			char dataHead; // S
			uint16 data1, data2, data3;
			ss >> dataHead >> data1 >> data2 >> data3;
			//sLog->outError("Zul'aman loaded, %d %d %d.", data1, data2, data3);
			if (dataHead == 'S')
			{
				BossKilled = data1;
				ChestLooted = data2;
				QuestMinute = data3;
			}
			else sLog->outError("Zul'aman: corrupted save data.");
		}

		void SetData(uint32 type, uint32 data)
		{
			switch (type)
			{
			case DATA_GONGEVENT:
				m_auiEncounter[DATA_GONGEVENT] = data;
				if (data == IN_PROGRESS)
					SaveToDB();
				else if (data == DONE)
					QuestMinute = 21;
				break;
			case DATA_NALORAKKEVENT:
				m_auiEncounter[DATA_NALORAKKEVENT] = data;
				if (data == DONE)
				{
					if (QuestMinute)
					{
						QuestMinute += 15;
						DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute);
					}
					SummonHostage(0);
					SaveToDB();
				}
				break;
			case DATA_AKILZONEVENT:
				m_auiEncounter[DATA_AKILZONEVENT] = data;
				HandleGameObject(AkilzonDoorGUID, data != IN_PROGRESS);
				if (data == DONE)
				{
					if (QuestMinute)
					{
						QuestMinute += 10;
						DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute);
					}
					SummonHostage(1);
					SaveToDB();
				}
				break;
			case DATA_JANALAIEVENT:
				m_auiEncounter[DATA_JANALAIEVENT] = data;
				if (data == DONE)
					SummonHostage(2);
				SaveToDB();
				break;
			case DATA_HALAZZIEVENT:
				m_auiEncounter[DATA_HALAZZIEVENT] = data;
				//HandleGameObject(HalazziDoorGUID, data != IN_PROGRESS);
				HandleGameObject(ZulJinGateGUID, data != IN_PROGRESS);
				if (data == DONE) SummonHostage(3);
				SaveToDB();
				break;
			case DATA_HEXLORDEVENT:
				m_auiEncounter[DATA_HEXLORDEVENT] = data;
				if (data == IN_PROGRESS)
					HandleGameObject(HexLordGateGUID, false);
				else if (data == NOT_STARTED)
					CheckInstanceStatus();
				SaveToDB();
				break;
			case DATA_ZULJINEVENT:
				m_auiEncounter[DATA_ZULJINEVENT] = data;
				HandleGameObject(ZulJinDoorGUID, data != IN_PROGRESS);
				SaveToDB();
				break;
			case DATA_CHESTLOOTED:
				++ChestLooted;
				SaveToDB();
				break;
			case TYPE_RAND_VENDOR_1:
				RandVendor[0] = data;
				break;
			case TYPE_RAND_VENDOR_2:
				RandVendor[1] = data;
				break;
			}

			if (data == DONE)
			{
				++BossKilled;
				if (QuestMinute && BossKilled >= DATA_HALAZZIEVENT)
				{
					QuestMinute = 0;
					DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0);
				}
				CheckInstanceStatus();
				SaveToDB();
			}
		}

		uint32 GetData(uint32 type) const
		{
			switch (type)
			{
			case DATA_GONGEVENT:     return m_auiEncounter[DATA_GONGEVENT];
			case DATA_NALORAKKEVENT: return m_auiEncounter[DATA_NALORAKKEVENT];
			case DATA_AKILZONEVENT:  return m_auiEncounter[DATA_AKILZONEVENT];
			case DATA_JANALAIEVENT:  return m_auiEncounter[DATA_JANALAIEVENT];
			case DATA_HALAZZIEVENT:  return m_auiEncounter[DATA_HALAZZIEVENT];
			case DATA_HEXLORDEVENT:  return m_auiEncounter[DATA_HEXLORDEVENT];
			case DATA_ZULJINEVENT:   return m_auiEncounter[DATA_ZULJINEVENT];
			case DATA_CHESTLOOTED:   return ChestLooted;
			case TYPE_RAND_VENDOR_1: return RandVendor[0];
			case TYPE_RAND_VENDOR_2: return RandVendor[1];
			default:                 return 0;
			}
		}

		void Update(uint32 diff)
		{
			if (QuestMinute)
			{
				if (QuestTimer <= diff)
				{
					QuestMinute--;
					SaveToDB();
					QuestTimer += 60000;
					if (QuestMinute)
					{
						DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1);
						DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, QuestMinute);
					}
					else DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0);
				}
				QuestTimer -= diff;
			}
		}

		uint64 GetData64(uint32 type) const
		{
			switch (type)
			{
			case GO_STRANGE_GONG:
				return StrangeGongGUID;
			case GO_MASSIVE_GATE:
				return MassiveGateGUID;
			case GO_DOOR_HALAZZI:
				return HalazziDoorGUID;
			}

			return 0;
		}

	};

	InstanceScript* GetInstanceScript(InstanceMap* map) const
	{
		return new instance_zulaman_InstanceMapScript(map);
	}
};

void AddSC_instance_zulaman()
{
	new instance_zulaman();
}

